package com.sk.bilibili.service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sk.bilibili.bean.*;
import com.sk.bilibili.dto.VideoSetInfo;
import com.sk.bilibili.event.BiliBiliEvent;
import com.sk.bilibili.other.R;
import com.sk.bilibili.utils.DbUtils;
import com.sk.bilibili.utils.BSessionUtils;
import com.sk.bilibili.utils.QueryWrapperUtils;
import com.sk.bilibili.utils.RedisUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.springframework.beans.factory.annotation.Autowired;
import com.sk.bilibili.mapper.VideoSetMapper;

/**
* @author 邵康
* @date 2021/11/23 16:10
*/
@Service
public class VideoSetService extends ServiceImpl<VideoSetMapper,VideoSet> {

    @Autowired
    private MinioService minioService;
    @Autowired
    private MemberService memberService;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private DbUtils dbUtils;
    @Autowired
    private VideoService videoService;
    @Autowired
    private PraiseService praiseService;
    @Autowired
    private CoinService coinService;
    @Autowired
    private CollectService collectService;
    @Autowired
    private TypeService typeService;
    @Autowired
    private ApplicationEventPublisher eventPublisher;
    private static final String COVER_PATH="videoSet/cover/%s.jpg";
    private static final Pattern COVER_PATTERN=Pattern.compile("/(videoSet/cover/.*jpg)");

    public R<Void> add(VideoSet videoSet) {
        int memberId = BSessionUtils.getMemberId();
        videoSet.setCover(minioService.add(videoSet.getCoverFile(),COVER_PATH));
        videoSet.setMemberId(memberId);
        if(videoSet.getInfo()==null)videoSet.setInfo(videoSet.getTitle());
        save(videoSet);
        eventPublisher.publishEvent(new BiliBiliEvent<>(this,videoSet));
        return R.success();
    }

    public R<Void> delete(Integer id) {
        VideoSet temp = getById(id);
        minioService.delete(temp.getCover(),COVER_PATTERN);
        removeById(id);
        return R.success();
    }

    public R<Void> update(VideoSet videoSet) {
        VideoSet temp = getById(videoSet.getId());
        String cover = minioService.update(COVER_PATH, COVER_PATTERN, temp.getCover(), videoSet.getCoverFile());
        videoSet.setCover(cover);
        updateById(videoSet);
        return R.success();
    }

    public R<IPage<VideoSet>> page(Integer page, Integer size, Integer typeId) {
        QueryWrapper<VideoSet> queryWrapper = null;
        if(typeId!=null){
            queryWrapper=QueryWrapperUtils.eq("type_id", typeId);
        }
        IPage<VideoSet> res = page(new Page<>(page, size), queryWrapper);
        res.getRecords().forEach(this::warpMember);
        return R.success(res);
    }

    public R<List<VideoSet>> getRandom(Integer size, Integer typeId) {
        List<VideoSet> list = baseMapper.getRandom(size, typeId);
        list.forEach(this::warpMember);
        return R.success(list);
    }

    private void warpMember(VideoSet videoSet) {
        videoSet.getExtra().addExtra(memberService.getById(videoSet.getMemberId()));
    }

    public R<List<VideoSet>> getRank(Integer size, Integer typeId) {
        QueryWrapper<VideoSet> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("praise_num");
        if(typeId!=null)queryWrapper.eq("type_id",typeId);
        queryWrapper.last("limit "+size);
        List<VideoSet> list = list(queryWrapper);
        warpFocusMember(list);
        return R.success(list);
    }

    private void warpFocusMember(List<VideoSet> videoSets) {
        int memberId = BSessionUtils.getMemberId();
        for (VideoSet videoSet:videoSets){
            Member member = memberService.getById(videoSet.getMemberId());
            memberService.warpFocus(memberId,member);
            videoSet.getExtra().addExtra(member);
        }
    }

    public void changeNum(String Field, Integer num, Integer id) {
        redisUtils.changeNum("VideoSet-"+id,Field,num);
    }

    public R<IPage<VideoSet>> getVideoSets(VideoSetInfo videoSetInfo) {
        if(videoSetInfo.getMemberId()==null)videoSetInfo.setMemberId(BSessionUtils.getMemberId());
        QueryWrapper<VideoSet> queryWrapper=QueryWrapperUtils.eq("member_id",videoSetInfo.getMemberId());
        queryWrapper.eq(videoSetInfo.getTypeId()!=null,"type_id",videoSetInfo.getTypeId());
        queryWrapper.orderByDesc(videoSetInfo.getColumn());
        return R.success(page(videoSetInfo.page(),queryWrapper));
    }

    public R<VideoSet> getVideoSet(Integer videoSetId) {
        // 封装信息
        VideoSet videoSet = getVideoSetWithVideos(videoSetId);
        warpMember(videoSet);
        int memberId = BSessionUtils.getMemberId();
        Member member = (Member) videoSet.getExtra().get("member");
        memberService.warpFocus(memberId,member);
        videoSet.getExtra().put("collect",collectService.getCollect(memberId,videoSetId));
        videoSet.getExtra().put("praise",praiseService.hasPraise(memberId,0,videoSetId));
        videoSet.getExtra().put("coin",coinService.hasCoin(memberId,0,videoSetId));
        changeNum("playNum",1,videoSetId);//增加播放量
        return R.success(videoSet);
    }

    public VideoSet getBaseVideoSet(Integer videoSetId) {
        VideoSet videoSet = getById(videoSetId);
        warpMember(videoSet);
        videoSet.getExtra().put("videoNum",videoService.getNum(videoSetId));
        int memberId = BSessionUtils.getMemberId();
        videoSet.getExtra().put("praise",praiseService.hasPraise(memberId,0,videoSetId));
        return videoSet;
    }

    /**
     * 获取基本的全面的视频信息
     */
    public VideoSet getVideoSetWithVideos(Integer id) {
        VideoSet videoSet = getById(id);
        videoSet.getExtra().addExtra(videoService.getVideos(id));
        return videoSet;
    }

    public R<IPage<VideoSet>> searchVideoSets(VideoSetInfo videoSetInfo) {
        if(videoSetInfo.getMemberId()==null)videoSetInfo.setMemberId(BSessionUtils.getMemberId());
        QueryWrapper<VideoSet> queryWrapper = QueryWrapperUtils.eq("member_id", videoSetInfo.getMemberId());
        queryWrapper.orderByDesc(videoSetInfo.getColumn());
        if(videoSetInfo.getTypeId()!=null)queryWrapper.eq("type_id",videoSetInfo.getTypeId());
        queryWrapper.like("title",videoSetInfo.getKeyword());
        return R.success(page(videoSetInfo.page(),queryWrapper));
    }

    public Integer getPlayNum(Integer memberId) {
        return baseMapper.getPlayNum(memberId);
    }

    public IPage<VideoSet> searchVideo(Page<VideoSet> page, QueryWrapper<VideoSet> queryWrapper) {
        IPage<VideoSet> iPage = page(page, queryWrapper);
        iPage.getRecords().forEach(this::warpMember);
        return iPage;
    }

    public Integer getVideoSetNum(Integer memberId) {
        QueryWrapper<VideoSet> queryWrapper = QueryWrapperUtils.eq("member_id", memberId);
        return count(queryWrapper);
    }

    @EventListener(condition = "event.type == 'com.sk.bilibili.service.CoinService.add'")
    public void handleCoinAdd(BiliBiliEvent<Coin> event){
        Coin coin = event.getData();
        if(coin.getType()!=0)return;
        changeNum("coinNum", coin.getNum(), coin.getTargetId());
    }

    @EventListener(condition = "event.type == 'com.sk.bilibili.service.CollectService.add'")
    public void handleCollectAdd(BiliBiliEvent<Collect> event){
        Collect collect = event.getData();
        changeNum("collectNum",1,collect.getVideoSetId());
    }

    @EventListener(condition = "event.type == 'com.sk.bilibili.service.CollectService.delete'")
    public void handleCollectDelete(BiliBiliEvent<Collect> event){
        Collect collect = event.getData();
        changeNum("collectNum",-1,collect.getVideoSetId());
    }

    @EventListener(condition = "event.type == 'com.sk.bilibili.service.DanmuService.add'")
    public void handleDanmuAdd(BiliBiliEvent<Danmu> event){
        Danmu danmu = event.getData();
        Video video = videoService.getById(danmu.getVideoId());
        changeNum("danmuNum",1,video.getVideoSetId());
    }

    @EventListener(condition = "event.type == 'com.sk.bilibili.service.VideoService.add'")
    public void handleVideoAdd(BiliBiliEvent<Video> event){
        Video video = event.getData();
        dbUtils.changeNum("video_set","duration",video.getDuration(),video.getVideoSetId());
    }

    public R<List<Type>> getSearchType(VideoSetInfo videoSetInfo) {
        List<Map<String,Long>> list=baseMapper.getSearchType(videoSetInfo);
        List<Type> res=typeService.getTypeList(list);
        return R.success(res);
    }

}
